package net.simflow.swf.analyzer.bgnetwork.opt;

import java.util.HashMap;

import net.simflow.swf.analyzer.bgnetwork.data.BGNetwork;
import net.simflow.swf.analyzer.bgnetwork.data.BGNode;
import net.simflow.swf.analyzer.network.data.Flow;
import net.simflow.swf.analyzer.network.data.Network;
import net.simflow.swf.analyzer.network.data.Service;

public class BGNetworkBuilder {

	private static BGNetworkBuilder instance = new BGNetworkBuilder();

	private BGNetworkBuilder() {
	}

	public static BGNetworkBuilder getInstance() {
		return instance;
	}

	public BGNetwork build(Network network) {
		if (network == null) {
			return null;
		}

		String name = null;
		if (network.getName() == Network.NETWORK) {
			name = BGNetwork.NETWORK;
		} else if (network.getName() == Network.SERVICE_NETWORK) {
			name = BGNetwork.SERVICE_NETWORK;
		}

		HashMap<Flow, BGNode> fmap = new HashMap<Flow, BGNode>();
		HashMap<Service, BGNode> smap = new HashMap<Service, BGNode>();

		for (Service svc : network.getServiceMap().values()) {
			smap.put(svc, new BGNode(svc));
		}

		for (Flow flow : network.getFlowMap().values()) {
			BGNode fn = new BGNode(flow);
			fmap.put(flow, fn);
			for (Service svc : flow.getServiceSet()) {
				BGNode sn = smap.get(svc);
				fn.addNeighbor(sn);
				sn.addNeighbor(fn);
			}
		}

		return new BGNetwork(name, fmap, smap);
	}

	public HashMap<Service, BGNode> buildBGService(BGNetwork bgNetwork) {
		if (bgNetwork == null) {
			return null;
		}

		BGNetwork bg = clone(bgNetwork);

		for (BGNode sn : bg.getServiceMap().values()) {
			sn.clearNeighborSet();
		}

		for (BGNode fn : bg.getFlowMap().values()) {
			for (BGNode sn : fn.getNeighborSet()) {
				sn.addNeighborSet(fn.getNeighborSet());
				sn.removeNeighbor(sn);
			}
		}

		return bg.getServiceMap();
	}

	public HashMap<Flow, BGNode> buildBGFlow(BGNetwork bgNetwork) {
		if (bgNetwork == null) {
			return null;
		}

		BGNetwork bg = clone(bgNetwork);

		for (BGNode fn : bg.getFlowMap().values()) {
			fn.clearNeighborSet();
		}

		for (BGNode sn : bg.getServiceMap().values()) {
			for (BGNode fn : sn.getNeighborSet()) {
				fn.addNeighborSet(sn.getNeighborSet());
				fn.removeNeighbor(fn);
			}
		}

		return bg.getFlowMap();
	}

	private BGNetwork clone(BGNetwork bg) {
		HashMap<BGNode, BGNode> fmap = new HashMap<BGNode, BGNode>();
		HashMap<BGNode, BGNode> smap = new HashMap<BGNode, BGNode>();

		for (BGNode oldn : bg.getFlowMap().values()) {
			BGNode newn = new BGNode(oldn.getFlow());
			fmap.put(oldn, newn);
		}

		for (BGNode oldn : bg.getServiceMap().values()) {
			BGNode newn = new BGNode(oldn.getService());
			smap.put(oldn, newn);
		}

		for (BGNode oldn : bg.getFlowMap().values()) {
			BGNode newn = fmap.get(oldn);
			for (BGNode oldnei : oldn.getNeighborSet()) {
				BGNode newnei = smap.get(oldnei);
				newn.addNeighbor(newnei);
			}
		}

		for (BGNode oldn : bg.getServiceMap().values()) {
			BGNode newn = smap.get(oldn);
			for (BGNode oldnei : oldn.getNeighborSet()) {
				BGNode newnei = fmap.get(oldnei);
				newn.addNeighbor(newnei);
			}
		}

		HashMap<Flow, BGNode> rfmap = new HashMap<Flow, BGNode>();
		HashMap<Service, BGNode> rsmap = new HashMap<Service, BGNode>();
		for (BGNode n : fmap.values()) {
			rfmap.put(n.getFlow(), n);
		}
		for (BGNode n : smap.values()) {
			rsmap.put(n.getService(), n);
		}

		return new BGNetwork(bg.getName(), rfmap, rsmap);
	}
}
